package ua.org.enginer.controls {
	
import flash.display.DisplayObject;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.text.TextLineMetrics;

import mx.binding.utils.ChangeWatcher;
import mx.controls.Button;
import mx.controls.LinkButton;
import mx.controls.TextInput;
import mx.core.ClassFactory;
import mx.core.IDataRenderer;
import mx.core.IFactory;
import mx.core.UIComponent;
import mx.core.UITextField;
import mx.events.FlexEvent;

//use namespace mx_internal;

//[Event(name="change", type="mx.events.Event")]

/**
 *  Name of the class to use as the edit icon. 
 *  
 *  @default ua/org/enginer/assets/icons/pencil.png 
 */
[Style(name="editIcon", type="Class", inherit="no")]

/**
 *  Name of the class to use as the commit icon. 
 *  
 *  @default ua/org/enginer/assets/icons/tick_circle_frame.png 
 */
[Style(name="commitIcon", type="Class", inherit="no")]

/**
 *  Name of the class to use as the commit icon. 
 *  
 *  @default ua/org/enginer/assets/icons/tick_circle_frame.png 
 */
[Style(name="canselIcon", type="Class", inherit="no")]

//include "../styles/TextStyles.as"
/**
 *  Color of text in the component, including the component label.
 *
 *  @default 0x0B333C
 */
[Style(name="color", type="uint", format="Color", inherit="yes")]

/**
 *  Color of text in the component if it is disabled.
 *
 *  @default 0xAAB3B3
 */
[Style(name="disabledColor", type="uint", format="Color", inherit="yes")]

/**
 *  Sets the <code>antiAliasType</code> property of internal TextFields. The possible values are 
 *  <code>"normal"</code> (<code>flash.text.AntiAliasType.NORMAL</code>) 
 *  and <code>"advanced"</code> (<code>flash.text.AntiAliasType.ADVANCED</code>). 
 *  
 *  <p>The default value is <code>"advanced"</code>, which enables advanced anti-aliasing for the font.
 *  Set to <code>"normal"</code> to disable the advanced anti-aliasing.</p>
 *  
 *  <p>This style has no effect for system fonts.</p>
 *  
 *  <p>This style applies to all the text in a TextField subcontrol; 
 *  you cannot apply it to some characters and not others.</p>

 *  @default "advanced"
 * 
 *  @see flash.text.TextField
 *  @see flash.text.AntiAliasType
 */
[Style(name="fontAntiAliasType", type="String", enumeration="normal,advanced", inherit="yes")]

/**
 *  Name of the font to use.
 *  Unlike in a full CSS implementation,
 *  comma-separated lists are not supported.
 *  You can use any font family name.
 *  If you specify a generic font name,
 *  it is converted to an appropriate device font.
 * 
 *  @default "Verdana"
 */
[Style(name="fontFamily", type="String", inherit="yes")]

/**
 *  Sets the <code>gridFitType</code> property of internal TextFields that represent text in Flex controls.
 *  The possible values are <code>"none"</code> (<code>flash.text.GridFitType.NONE</code>), 
 *  <code>"pixel"</code> (<code>flash.text.GridFitType.PIXEL</code>),
 *  and <code>"subpixel"</code> (<code>flash.text.GridFitType.SUBPIXEL</code>). 
 *  
 *  <p>This property only applies when you are using an embedded font 
 *  and the <code>fontAntiAliasType</code> property 
 *  is set to <code>"advanced"</code>.</p>
 *  
 *  <p>This style has no effect for system fonts.</p>
 * 
 *  <p>This style applies to all the text in a TextField subcontrol; 
 *  you can't apply it to some characters and not others.</p>
 * 
 *  @default "pixel"
 *  
 *  @see flash.text.TextField
 *  @see flash.text.GridFitType
 */
[Style(name="fontGridFitType", type="String", enumeration="none,pixel,subpixel", inherit="yes")]

/**
 *  Sets the <code>sharpness</code> property of internal TextFields that represent text in Flex controls.
 *  This property specifies the sharpness of the glyph edges. The possible values are Numbers 
 *  from -400 through 400. 
 *  
 *  <p>This property only applies when you are using an embedded font 
 *  and the <code>fontAntiAliasType</code> property 
 *  is set to <code>"advanced"</code>.</p>
 *  
 *  <p>This style has no effect for system fonts.</p>
 * 
 *  <p>This style applies to all the text in a TextField subcontrol; 
 *  you can't apply it to some characters and not others.</p>
 *  
 *  @default 0
 *  
 *  @see flash.text.TextField
 */
[Style(name="fontSharpness", type="Number", inherit="yes")]

/**
 *  Height of the text, in pixels.
 *
 *  The default value is 10 for all controls except the ColorPicker control. 
 *  For the ColorPicker control, the default value is 11. 
 */
[Style(name="fontSize", type="Number", format="Length", inherit="yes")]

/**
 *  Determines whether the text is italic font.
 *  Recognized values are <code>"normal"</code> and <code>"italic"</code>.
 * 
 *  @default "normal"
 */
[Style(name="fontStyle", type="String", enumeration="normal,italic", inherit="yes")]

/**
 *  Sets the <code>thickness</code> property of internal TextFields that represent text in Flex controls.
 *  This property specifies the thickness of the glyph edges.
 *  The possible values are Numbers from -200 to 200. 
 *  
 *  <p>This property only applies when you are using an embedded font 
 *  and the <code>fontAntiAliasType</code> property 
 *  is set to <code>"advanced"</code>.</p>
 *  
 *  <p>This style has no effect on system fonts.</p>
 * 
 *  <p>This style applies to all the text in a TextField subcontrol; 
 *  you can't apply it to some characters and not others.</p>
 *  
 *  @default 0
 *  
 *  @see flash.text.TextField
 */
[Style(name="fontThickness", type="Number", inherit="yes")]

/**
 *  Determines whether the text is boldface.
 *  Recognized values are <code>normal</code> and <code>bold</code>.
 *  The default value for Button controls is <code>bold</code>. 
 *  The default value for all other controls is <code>normal</code>.
 */
[Style(name="fontWeight", type="String", enumeration="normal,bold", inherit="yes")]

/**
 *  A Boolean value that indicates whether kerning
 *  is enabled (<code>true</code>) or disabled (<code>false</code>).
 *  Kerning adjusts the gap between certain character pairs
 *  to improve readability, and should be used only when necessary,
 *  such as with headings in large fonts.
 *  Kerning is supported for embedded fonts only. 
 *  Certain fonts, such as Verdana, and monospaced fonts,
 *  such as Courier New, do not support kerning.
 *
 *  @default false
 */
[Style(name="kerning", type="Boolean", inherit="yes")]

/**
 *  The number of additional pixels to appear between each character.
 *  A positive value increases the character spacing beyond the normal spacing,
 *  while a negative value decreases it.
 * 
 *  @default 0
 */
[Style(name="letterSpacing", type="Number", inherit="yes")]

/**
 *  Alignment of text within a container.
 *  Possible values are <code>"left"</code>, <code>"right"</code>,
 *  or <code>"center"</code>.
 * 
 *  <p>The default value for most components is <code>"left"</code>.
 *  For the FormItem component,
 *  the default value is <code>"right"</code>.
 *  For the Button, LinkButton, and AccordionHeader components,
 *  the default value is <code>"center"</code>, and
 *  this property is only recognized when the
 *  <code>labelPlacement</code> property is set to <code>"left"</code> or
 *  <code>"right"</code>.
 *  If <code>labelPlacement</code> is set to <code>"top"</code> or
 *  <code>"bottom"</code>, the text and any icon are centered.</p>
 */
[Style(name="textAlign", type="String", enumeration="left,center,right", inherit="yes")]

/**
 *  Determines whether the text is underlined.
 *  Possible values are <code>"none"</code> and <code>"underline"</code>.
 * 
 *  @default "none"
 */
[Style(name="textDecoration", type="String", enumeration="none,underline", inherit="yes")]

/**
 *  Offset of first line of text from the left side of the container, in pixels.
 * 
 *  @default 0
 */
[Style(name="textIndent", type="Number", format="Length", inherit="yes")]

[DefaultProperty(name="editor")]

public class EditableLabel1 extends UIComponent implements IDataRenderer {
	
	[Embed(source="ua/org/enginer/assets/icons/pencil.png")]
	private var defaultEditIcon:Class
	[Embed(source="ua/org/enginer/assets/icons/tick_circle_frame.png")]
	private var defaultCommitIcon:Class
	[Embed(source="ua/org/enginer/assets/icons/cross.png")]
	private var defaultCanselIcon:Class
	
	
	private var icon:DisplayObject
	private var mainButton:Button
	private var canselButton:Button
	private var renderer:UITextField
	//private var editor:UIComponent
	
	public function EditableLabel1() {
		super();
		addEventListener(MouseEvent.CLICK, onClick)
	}
	
	protected function onClick(event:MouseEvent):void {
		if (editable && !editMode) editMode = true
	}
	
	private var _text:String = null;
	private var _textChanged:Boolean
	public function set text(value:String):void {
		_text = value;
		_textChanged = true
		invalidateProperties()
		invalidateSize()
	}

	public function get text():String {
		if (_text) return _text
		if (data is String) return String(data)
		if (data is Object) return data[dataField]
		return ''
	}
	
	private var _prompt:String = "";
	private var _promptChanged:Boolean
	public function get prompt():String {
		return _prompt;
	}
	
	//[Bindable]
	public function set prompt(value:String):void	{
		_prompt = value;
		_promptChanged = true
		invalidateProperties();
		//invalidateDisplayList();
	}
	
	private var _promptFormat:String = '<font color="#999999"><i>[prompt]</i></font>';
	
	/** 
	 * A format string to specify how the prompt is displayed.  This is typically
	 * an HTML string that can set the font color and style.  Use <code>[prompt]</code>
	 * within the string as a replacement token that will be replaced with the actual
	 * prompt text.
	 * 
	 * The default value is "&lt;font color="#999999"&gt;&lt;i&gt;[prompt]&lt;/i&gt;&lt;/font&gt;"
	 */
	public function get promptFormat():String {
		return _promptFormat;
	}
	
	public function set promptFormat(value:String):void	{
		_promptFormat = value;
		// Check to see if the replacement code is found in the new format string
		if ( _promptFormat.indexOf( "[prompt]" ) < 0 )	{
			// TODO: Log error with the logging framework, or just use trace?
			//trace( "PromptingTextInput warning: prompt format does not contain [prompt] replacement code." );	
		}
		
		invalidateProperties()
	}
	
	private var _editable:Boolean;
	public function set editable(value:Boolean):void {
		_editable = value;
		invalidateProperties()
	}

	public function get editable():Boolean {
		return _editable;
	}

	private var _editMode:Boolean
	public function set editMode(value:Boolean):void {
		_editMode = value
		invalidateProperties()
	} 
	[Bindable]
	public function get editMode():Boolean {
		return _editMode
	}
	
	private var _editorRenderer:IFactory;
	private var _editorRendererChanged:Boolean
	public function set editorRenderer(value:IFactory):void {
		_editorRenderer = value;
		_editorRendererChanged = true
		invalidateProperties()
	}

	public function get editorRenderer():IFactory {
		return _editorRenderer;
	}

	private var _editor:DisplayObject;
	public function set editor(value:DisplayObject):void {
		_editor = value;
		invalidateProperties()
	}

	public function get editor():DisplayObject {
		return _editor;
	}
	
	private var _dataField:String = "label"
	private var _dataFieldChanged:Boolean
	public function set dataField(value:String):void {
		_dataField = value;
		invalidateProperties()
	}

	public function get dataField():String {
		return _dataField;
	}
	
	/**
     *  The name of the property of the item editor that contains the new
     *  data for the list item.
     *  For example, the default <code>editor</code> is
     *  TextInput, so the default value of the <code>editorDataField</code> 
     *  property is <code>"text"</code>, which specifies the 
     *  <code>text</code> property of the TextInput control.
     *
     *  @default "text"
     */
	private var _editorDataField:String;
	public function set editorDataField(value:String):void {
		_editorDataField = value;
	}

	public function get editorDataField():String {
		return _editorDataField
	}

	//public var preventChangeByEditor:Boolean

	override protected function createChildren():void {
		super.createChildren()
		
		renderer = new UITextField()
		renderer.text = text
		renderer.styleName = this
		addChild(renderer)
		
		mainButton = new LinkButton()
		canselButton = new LinkButton()
	}
	
	override protected function commitProperties():void {
		super.commitProperties()
		
		if (_dataFieldChanged || _dataChanged || _promptChanged || _textChanged)  {
			if (prompt && !text) {
				renderer.htmlText = promptFormat.replace(/\[prompt\]/g, prompt)
			}else 
				renderer.text = text
			
			if(_editor) {
				//if (_editor.hasOwnProperty('text')) _editor['text'] = ''
				//if (owns(_editor)) removeChild(_editor)
				//_editor = null
			}
			
			_dataChanged = false
			_textChanged = false
			_dataFieldChanged = false
			_promptChanged = false
			//editMode = false
		}
		
		editMode = editMode && editable
		renderer.visible = !editMode
		
		if (editable && editMode) {
			if ((!editor && editorRenderer) || _editorRendererChanged) {
				editor = editorRenderer.newInstance()
				_editorRendererChanged = false
			}
			if (!editor) editor = new ClassFactory(TextInput).newInstance()
			
			IDataRenderer(editor).data = text
			
			editor.addEventListener(Event.CHANGE, onChange)
			
			addChild(editor)
			invalidateSize()
		}
		else if (!editable || !editMode) {
			if (editor && owns(editor)) removeChild(editor)
		}
		
		// icon
		if (editable) {
			//icon = getIcon()
			
			//button.label = "edit"
			//button.useHandCursor = true
			//button.mouseEnabled = false
			//button.mouseChildren = true
			//button.styleName = new StyleProxy(this, null)
			//button.setStyle("icon", getIcon())
			mainButton.setStyle("icon", getIcon())
			if (!owns(mainButton)) {
				addChild(mainButton)
				mainButton.addEventListener(FlexEvent.BUTTON_DOWN, editButtonDownHandler)
	            mainButton.invalidateDisplayList();
   			}

   			/*
			if (!owns(canselButton)) {
				var icon:Class = getStyle("canselIcon")
				canselButton.setStyle("icon", icon ? icon : defaultCanselIcon)
				addChild(canselButton)
				canselButton.addEventListener(FlexEvent.BUTTON_DOWN, canselButtonDownHandler)
	            canselButton.invalidateDisplayList();
   			}
   			*/
		}
		if ((!editable || (editable && editMode)) && mainButton && owns(mainButton)) {
			removeChild(mainButton)
		}
		/*
		if (!editMode && canselButton && owns(canselButton)) {
			removeChild(canselButton)
		}
		*/
		invalidateSize()
	}
	
	override protected function measure():void {
		super.measure()
		
		var textWidth:Number = 0;
        var textHeight:Number = 0;

        if (renderer.text) {
            var lineMetrics:TextLineMetrics = measureText(renderer.text);
            textWidth = lineMetrics.width + 4;
            textHeight = lineMetrics.height + 3;
        }
        
        renderer.width = textWidth
		renderer.height = textHeight
		renderer.y = 2
		
		var iconWidth:Number = 22;
        var iconHeight:Number = 22;
		
		
		
		var w:Number = textWidth
        var h:Number = textHeight
        /*
        if (editMode) {
        	w = Math.max(w, editorInst.measuredWidth)
        	h = Math.max(h, editorInst.height)
        }*/
        
        if (editMode) {
        	w = Math.max(textWidth + 10, UIComponent.DEFAULT_MEASURED_WIDTH);
        	h = Math.max(textHeight + 5, UIComponent.DEFAULT_MEASURED_HEIGHT);
        	editor.width = w
        	editor.height = h
        }
		
		if (owns(mainButton)) {
			mainButton.setActualSize(iconWidth, iconHeight)
			mainButton.move(w, 0)
		}
		
		if (owns(canselButton)) {
			canselButton.setActualSize(iconWidth, iconHeight)
			canselButton.move(w+iconWidth, 0)
			w += iconWidth
		}
		
		measuredMinWidth = measuredWidth = w + iconWidth
		measuredMinHeight = measuredHeight = Math.max(h, iconHeight)
	}
	
	
	protected function getIcon():Class {
		var icon:Class
		
		if (!editMode) {
			icon = getStyle("editIcon")
			icon = icon ? icon : defaultEditIcon
		}else {
			icon = getStyle("commitIcon")
			icon = icon ? icon : defaultCommitIcon
		}
		
		return icon
	}
	
	private function editButtonDownHandler(event:FlexEvent):void {
		//if (editable && !editMode) 
			editMode = true
		//else 
		//if (editable && !preventChangeByEditor) 
			//commitEditorData()
	}
	/*
	private function canselButtonDownHandler(event:FlexEvent):void {
		editMode = false
	}
	*/
	//*
	public var commitDataFunction:Function
	
	protected function commitEditorData():void {
		if (!commitDataFunction) {
			if (data is String || !data) data = editorDataField ? editor[editorDataField] : editor['text']
			else if (data is Object) data[dataField] = editorDataField ? editor[editorDataField] : editor['text']
		}else {
			commitDataFunction(editor)
		}
		//text = 
		//editMode = false
		//var event:Event = new Event(Event.CHANGE)
		//event.currentTarget = editorInst
		//dispatchEvent(event)
	}
	//*/
	
	override public function styleChanged(styleProp:String):void {
        if (mainButton)
            mainButton.styleChanged(styleProp);

        super.styleChanged(styleProp);
    }
    
    
	private var _data:Object;
	private var _dataChanged:Boolean;
	public function set data(value:Object):void {
		_data = value;
		_dataChanged = true
		ChangeWatcher.watch(_data, dataField, onDataChange)
		invalidateProperties()
	}

	public function get data():Object {
		return _data;
	}

    protected function onDataChange(event:Event):void {
    	//trace("d")
    	//if (!editMode) {
    		_dataChanged = true
    		invalidateProperties()
    	//}
    }	
    
    protected function onChange(event:Event):void {
    	commitEditorData()
    }
}
}

